package index;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Pattern;

import org.htmlparser.beans.StringBean;

import text.ChineseStem;
import utils.Util;

/**
 * there is no any connection between this class and the cache data, it does not
 * store the data but only a set of some terms.
 * 
 * @author huangcd
 * 
 */
public class Document
{
    private static Map<Integer, Document> documentsMap;
    // identify of this document
    private int                           documentID;
    // all appearance terms in this document
    private Set<Term>                     contents;
    // total term count of this document
    private int                           totalCount;

    static
    {
        documentsMap = Collections
                .synchronizedMap(new HashMap<Integer, Document>());
    }

    /**
     * get a document instance by its id, if the document does not exists,
     * create a new one. <br>
     * if the documentID equals -2, it means that the document is built from the
     * query string
     * 
     * @param documentID
     * @return
     */
    public static synchronized Document getDocument(int documentID)
    {
        if (documentsMap.containsKey(documentID))
            return documentsMap.get(documentID);
        Document value = new Document(documentID);
        documentsMap.put(documentID, value);
        return value;
    }

    public static synchronized void clean()
    {
        documentsMap.clear();
    }

    /**
     * return a collection contains all the documents
     * 
     * @return
     */
    public static synchronized Collection<Document> getAllDocuments()
    {
        return documentsMap.values();
    }

    /**
     * return the number of documents
     * 
     * @return
     */
    public static synchronized int getDocumentsCount()
    {
        return documentsMap.values().size();
    }

    public static synchronized boolean delete(int id)
    {
        if (!documentsMap.containsKey(id))
            return false;
        Document doc = documentsMap.get(id);
        for (Term t : doc.contents)
        {
            t.delete(doc);
        }
        documentsMap.remove(id);
        return true;
    }

    private Document(int documentID)
    {
        this.documentID = documentID;
        totalCount = 0;
        contents = Collections.synchronizedSet(new HashSet<Term>());
    }

    public void addTerm(String name, double weight)
    {
        Term t = Term.getTerm(name);
        t.addPageWeight(weight, this);
        contents.add(t);
        totalCount++;
        if (totalCount > Util.getMaxPageTermCount())
            Util.setMaxPageTermCount(totalCount);
    }

    public void addTerm(Term term)
    {
        contents.add(term);
    }

    /**
     * return the id of this document
     * 
     * @return
     */
    public int getDocumentID()
    {
        return documentID;
    }

    public Set<Term> getContent()
    {
        return contents;
    }

    public double getMaxWeight()
    {
        double max = -1;
        for (Term t : contents)
        {
            double weight = t.getWeight(this);
            max = Math.max(max, weight);
        }
        return max;
    }

    /**
     * return the distance of this document and the original point
     * 
     * @return
     */
    public double getLength()
    {
        double sum = 0;
        for (Term t : contents)
        {
            double weight = t.getWeight(this);
            sum += weight * weight;
        }
        return Math.sqrt(sum);
    }

    public String getDisplayHtmlContent(String url, String queryResult,
            double sim)
    {
        queryResult = queryResult.toLowerCase();
        StringBuilder str = new StringBuilder();
        str.append("<td><tr><font size=\"14px\">\n");
        StringBean sb = new StringBean();
        sb.setURL("file:/" + Util.getHome() + "/cache/" + documentID);
        sb.setLinks(false);
        String contents = sb.getStrings().toLowerCase();
        int index = contents.indexOf('\n');
        String tmp = contents.substring(0, index).trim();
        contents = contents.substring(index).replaceAll("\\s+", "");
        tmp = tmp.replace("<title>", "").replace("</title>", "").trim();
        str.append("<a href=\"").append(url).append("\">").append(tmp).append(
                "</a><br/>");
        if (contents.contains(queryResult))
        {
            int start = contents.indexOf(queryResult) - 40;
            if (start < 0)
            {
                start = contents.indexOf(queryResult, start + 40);
                if (start < 0)
                {
                    start = 0;
                }
            }
            int end = start + queryResult.length() + 80;
            str.append(contents.substring(start, Math.min(end, contents
                    .length())));
        }
        else
        {
            str
                    .append(contents.substring(50, Math.min(150, contents
                            .length())));
        }
        str.append("</font>\n<br/><font size=\"8px\">（相似度:").append(sim)
                .append(")</font>");
        str.append("\n</td></tr>\n");
        Scanner scan = new Scanner(ChineseStem.parse(queryResult));
        String result = str.toString();
        while (scan.hasNext())
        {
            String s = scan.next();
            result = Pattern.compile(s, Pattern.CASE_INSENSITIVE).matcher(
                    result).replaceAll(
                    "<font color=\"#ff0000\">" + s + "</font>");
        }
        return result;
    }

    /**
     * return the number of words contains in this document, notice that a term
     * may appear several times in a document
     * 
     * @return
     */
    public int getTermCount()
    {
        return totalCount;
    }
}
